package com.fcc.wfly.printhead.service.impl;

import com.fcc.wfly.printhead.dao.PrintheadDao;
import com.fcc.wfly.printhead.domain.*;
import com.fcc.wfly.printhead.domain.constant.StateConstant;
import com.fcc.wfly.printhead.service.DeviceUtilizationVo;
import com.fcc.wfly.printhead.service.PrintheadService;
import com.fcc.wfly.printhead.service.MaintenanceEventsVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service("printheadService")
public class PrintheadServiceImpl implements PrintheadService {

	@Autowired
	private PrintheadDao printheadDao;

	private static SimpleDateFormat yyyyMMddHH = new SimpleDateFormat("yyyyMMddHH");

	@Override
	public List<PrinterStateResult> getPrinterStateResultList(String pn, String sn, String startDate, String endDate, String channel) {
		List<PrinterStateResult> list = printheadDao.getPrinterStateResultList(pn, sn, Timestamp.valueOf(startDate), Timestamp.valueOf(endDate), channel);
		if (list != null && list.size() > 0) {
			if (Timestamp.valueOf(list.get(0).getStartDate()).getTime() < Timestamp.valueOf(startDate).getTime()) {
				list.get(0).setStartDate(startDate);
			}
			if (Timestamp.valueOf(list.get(list.size() - 1).getEndDate()).getTime() > Timestamp.valueOf(endDate).getTime()) {
				list.get(list.size() - 1).setEndDate(endDate);
			}
			for (PrinterStateResult o : list) {
				o.setStartTime(Timestamp.valueOf(o.getStartDate()).getTime());
				o.setEndTime(Timestamp.valueOf(o.getEndDate()).getTime());
			}
		}
		return list;
	}

	@Override
	public DeviceUtilizationVo getDeviceUtilization(String pn, String sn, String startDate, String endDate) {
		// query all printer state result
		List<PrinterStateResult> allStateList = getPrinterStateResultList(pn, sn, startDate, endDate, StateConstant.CHANNEL_ALL);

		Long startTime = Timestamp.valueOf(startDate).getTime(), endTime = Timestamp.valueOf(endDate).getTime(), //
				totalTime = endTime - startTime, noDataTime = 0L, idleTime = 0L, offTime = 0L, downTime = 0L, productiveTime = 0L, onTime = 0L;
		if (!allStateList.isEmpty()) {
			// calculate idle/down/off time
			for (int i = 0; i < allStateList.size(); i++) {
				String st = allStateList.get(i).getStatus();
				Long d = allStateList.get(i).getEndTime() - allStateList.get(i).getStartTime();
				if (null != d) {
					if (StateConstant.IDLE.equals(st)) {
						idleTime += d;
					} else if (StateConstant.DOWN.equals(st)) {
						downTime += d;
					} else if (StateConstant.OFF.equals(st)) {
						offTime += d;
					}
				}
			}
			// calculate no data time
			PrinterStateResult state = allStateList.get(0);
			noDataTime += state.getStartTime() - startTime;
			for (int i = 1; i < allStateList.size(); i++) {
				noDataTime += allStateList.get(i).getStartTime() - state.getEndTime();
				state = allStateList.get(i);
			}
			noDataTime += endTime - state.getEndTime();
			// calculate productive time
			productiveTime = totalTime - downTime - idleTime - offTime - noDataTime;
			// calculate on time
			onTime = totalTime - downTime - offTime - noDataTime;
		}
		DeviceUtilizationVo deviceUtilization = new DeviceUtilizationVo();
		deviceUtilization.setProductiveHours(String.format("%.4f", productiveTime / 3600000d));
		deviceUtilization.setOnHours(String.format("%.4f", onTime / 3600000d));
		return deviceUtilization;
	}

	@Override
	public List<MaintenanceDetail> getMaintenanceDetailList(String sn, String startDate, String endDate) {
		long startTime = Long.valueOf(yyyyMMddHH.format(Timestamp.valueOf(startDate + " 00:00:00")));
		Calendar endCal = Calendar.getInstance();
		endCal.setTime(Timestamp.valueOf(endDate + " 00:00:00"));
		endCal.add(Calendar.DATE, 1);
		long endTime = Long.valueOf(yyyyMMddHH.format(endCal.getTime()));
		List<MaintenanceDetail> list = printheadDao.getMaintenanceDetailList(sn, startTime, endTime);
		return list;
	}

	@Override
	public List<MaintenanceDetail> getMaintenanceDetailTaskList(String sn, String date) {
		List<MaintenanceDetail> list = getMaintenanceDetailList(sn, date, date);
		if (list == null || list.size() == 0) {
			Calendar dateCal = Calendar.getInstance();
			dateCal.setTime(Timestamp.valueOf(date + " 00:00:00"));
			dateCal.add(Calendar.DATE, 1);
			long dateTime = Long.valueOf(yyyyMMddHH.format(dateCal.getTime()));
			list = printheadDao.getMaintenanceDetailGroupPartNameList(sn, dateTime);
		}
		return list;
	}

	@Override
	public MaintenanceEventsVo getMaintenanceEvents(String sn, String startDate, String endDate) {
		// query all maintenance details
		List<MaintenanceDetail> maintenanceDetailList = getMaintenanceDetailList(sn, startDate, endDate);

		// if first day no data, need to query the latest data before startDate.
		boolean firstDayHasData = false;
		if (maintenanceDetailList != null && maintenanceDetailList.size() > 0) {
			MaintenanceDetail firstDayMaintenanceDetail = maintenanceDetailList.get(0);
			if (startDate.replace("-", "").equals(firstDayMaintenanceDetail.getLastUpdate().substring(0, 8))) {
				firstDayHasData = true;
			}
		}
		if (!firstDayHasData) {
			Calendar dateCal = Calendar.getInstance();
			dateCal.setTime(Timestamp.valueOf(startDate + " 00:00:00"));
			dateCal.add(Calendar.DATE, 1);
			long dateTime = Long.valueOf(yyyyMMddHH.format(dateCal.getTime()));
			List<MaintenanceDetail> firstDayMaintenanceDetailList = printheadDao.getMaintenanceDetailGroupPartNameList(sn, dateTime);
			firstDayMaintenanceDetailList.addAll(maintenanceDetailList);
			maintenanceDetailList = firstDayMaintenanceDetailList;
		}

		// calculate maintenance events
		int totalEvents = 0, addressedEvents = 0;
		Map<String, MaintenanceDetail> map = new HashMap<String, MaintenanceDetail>();
		for (MaintenanceDetail maintenanceDetail : maintenanceDetailList) {
			try {
				int counter = Integer.valueOf(maintenanceDetail.getCounter());
				int freqDays = Integer.valueOf(maintenanceDetail.getFreqDays());
				if (counter > freqDays) {
					if (!map.containsKey(maintenanceDetail.getPartName())) {
						totalEvents++;
					} else {
						MaintenanceDetail prevMaintenanceDetail = map.get(maintenanceDetail.getPartName());
						int prevCounter = Integer.valueOf(prevMaintenanceDetail.getCounter());
						int prevFreqDays = Integer.valueOf(prevMaintenanceDetail.getFreqDays());
						// if %Progression Maint gone down
						if ((counter / freqDays) < (prevCounter / prevFreqDays)) {
							Calendar dateCal = Calendar.getInstance();
							dateCal.setTime(yyyyMMddHH.parse(prevMaintenanceDetail.getLastUpdate()));
							dateCal.add(Calendar.DATE, 1);
							String prevLastUpdateAdd1day = yyyyMMddHH.format(dateCal.getTime());
							// if exists no data day in the middle
							if (Long.valueOf(maintenanceDetail.getLastUpdate().substring(0, 8)) > Long.valueOf(prevLastUpdateAdd1day.substring(0, 8))) {
								totalEvents++;
								addressedEvents++;
							}
						}
					}
					map.put(maintenanceDetail.getPartName(), maintenanceDetail);
				} else {
					if (map.containsKey(maintenanceDetail.getPartName())) {
						map.remove(maintenanceDetail.getPartName());
						addressedEvents++;
					}
				}
			} catch (Exception e) {
			}
		}
		MaintenanceEventsVo maintenanceEvents = new MaintenanceEventsVo();
		maintenanceEvents.setTotalEvents(totalEvents);
		maintenanceEvents.setAddressedEvents(addressedEvents);
		return maintenanceEvents;
	}

	@Override
	public List<PrntrLogDtl> getPrntrLogDtlList(String pn, String sn, String startDate, String endDate) {
		List<PrntrLogDtl> list = printheadDao.getPrntrLogDtlList(pn, sn, Timestamp.valueOf(startDate), Timestamp.valueOf(endDate));
		if (list != null && list.size() > 0) {
			return list;
		}
		else{
			return printheadDao.get3DPrntrLogDtlList(pn, sn, Timestamp.valueOf(startDate), Timestamp.valueOf(endDate));
		}	
	}

	@Override
	public List<PrintheadEvent> getPrintheadEventList(String pn, String sn, String startDate, String endDate) {
		return printheadDao.getPrintheadEventList(pn, sn, Timestamp.valueOf(startDate), Timestamp.valueOf(endDate));
	}

	@Override
	public List<PrintheadWarrantyStatus> getPrintheadWarrantyStatusList(String pn, String sn, String startDate, String endDate) {
		return printheadDao.getPrintheadWarrantyStatusList(pn, sn, Timestamp.valueOf(startDate), Timestamp.valueOf(endDate));
	}

	@Override
	public List<PrinterStateResult> getPrinterStateResultAllChannelList(String pn, String sn, String startDate, String endDate) {
		List<PrinterStateResult> list = printheadDao.getPrinterStateResultAllChannelList(pn, sn, Timestamp.valueOf(startDate), Timestamp.valueOf(endDate));
		if (list != null && list.size() > 0){
			return list;
		}
		else{
			return printheadDao.get3DPrinterStateResultAllChannelList(pn, sn, Timestamp.valueOf(startDate), Timestamp.valueOf(endDate));
		}
	}
	
	@Override
	public List<PrinterStateResult> get3DPrinterStateResultAllChannelList(String pn, String sn, String startDate, String endDate) {
		List<PrinterStateResult> list = printheadDao.getPrinterStateResultAllChannelList(pn, sn, Timestamp.valueOf(startDate), Timestamp.valueOf(endDate));
		if (list != null && list.size() > 0){
			return list;
		}
		else{
			return printheadDao.get3DPrinterStateResultAllChannelList(pn, sn, Timestamp.valueOf(startDate), Timestamp.valueOf(endDate));
		}
	}

	@Override
	public List<PrntrLogDtl> get3DPrntrLogDtlList(String pn, String sn, String startDate, String endDate) {
		List<PrntrLogDtl> list = printheadDao.getPrntrLogDtlList(pn, sn, Timestamp.valueOf(startDate), Timestamp.valueOf(endDate));
		if (list != null && list.size() > 0) {
			return list;
		}
		else{
			return printheadDao.get3DPrntrLogDtlList(pn, sn, Timestamp.valueOf(startDate), Timestamp.valueOf(endDate));
		}
	}
}